/**
 * This class returns all events to remind the user of his to-do's
 * It sorts all events
 * 1- Overdue Events
 * 2- Starred Events
 * 3- Regular Events
 * @author Harsha Narayan
 * @author Vaarnan Drolia
 */

package action;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;

import storage.DataManager;
import data.Event;
import data.EventDateTime;

public class Reminder extends Action implements DataMiner
{

	private Overdue overdueObj = new Overdue();
	private Archive archiveObj = new Archive();

	/**
	 * @param userCommand
	 * @return Event[] of all events, sorted to remind
	 */
	@Override
	public Event[] execute(String userCommand) {
		return reminder(getAllEvents());
	}

	/**
	 * 
	 * @param allEvents
	 * @return Event[] of all events sorted for reminding
	 */
	public Event[] reminder(Event[] allEvents) {

		if (allEvents == null || allEvents.length == 0) {
			return allEvents;
		}
		ArrayList<Event> allEventsList = new ArrayList<Event>();
		ArrayList<Event> reminderList = new ArrayList<Event>();
		allEventsList.addAll(Arrays.asList(allEvents));
		
		Event[] archiveEvents = archiveObj.archive(new Event());
		if (archiveEvents != null) {
			allEventsList.removeAll(Arrays.asList(archiveEvents));
		}
		Event[] overdueEvents = overdueObj.overdue(allEvents);
		ArrayList<Event> overdueEventList = new ArrayList<Event>();
		if (overdueEvents != null) {
			overdueEventList.addAll(Arrays.asList(overdueEvents));
		}
		
		reminderList.addAll(sort(overdueEventList));
		allEventsList.removeAll(overdueEventList);

		ArrayList<Event> starredEvents = sort(getAllStarred(allEventsList));
		reminderList.addAll(starredEvents);
		allEventsList.removeAll(starredEvents);
		reminderList.addAll(sort(allEventsList));

		return (Event[]) reminderList.toArray(new Event[reminderList.size()]);
	}

	/**
	 * 
	 * @param allEvents
	 * @return ArrayList of all starred events
	 */
	public ArrayList<Event> getAllStarred(ArrayList<Event> allEvents) {

		ArrayList<Event> starredEvents = new ArrayList<Event>();
		for (int i = 0; i < allEvents.size(); i++) {
			if (allEvents.get(i).getStarred()) {
				starredEvents.add(allEvents.get(i));
			}
		}
		return starredEvents;
	}

	/**
	 * 
	 * @param listOfEvents
	 * @return sorted arraylist of events passes as param
	 */
	private ArrayList<Event> sort(ArrayList<Event> listOfEvents) {

		String[][] timeAndIdOfEvents = time_And_Id(listOfEvents);
		if (timeAndIdOfEvents == null) {
			return new ArrayList<Event>();
		}
		if (timeAndIdOfEvents != null) {
			sort2dArray(timeAndIdOfEvents);
		}
		ArrayList<Event> sortedList = new ArrayList<Event>();
		for (int i = 0; i < timeAndIdOfEvents.length; i++) {
			sortedList.add(DataManager.getEventById(timeAndIdOfEvents[i][1]));
		}

		return sortedList;
	}

	/**
	 * Function converts an ArrayList of events into
	 * a two-dimensional String array of the Event Start Times in long and its Id
	 * @param arrayListOfEvents
	 * @return
	 */
	private String[][] time_And_Id(ArrayList<Event> arrayListOfEvents) {
		String[][] timeId = new String[arrayListOfEvents.size()][2];
		long defaultTimeMillis = new EventDateTime().getTimeInMilli();
		if (arrayListOfEvents.size() == 0)
			return null;

		for (int i = 0; i < arrayListOfEvents.size(); i++) {

			long eventTime = arrayListOfEvents.get(i).getStart().getTimeInMilli();
			if (eventTime == defaultTimeMillis) {
				eventTime = Long.MAX_VALUE;
			}
			timeId[i][0] = Long.toString(eventTime);
			timeId[i][1] = arrayListOfEvents.get(i).getId();
		}

		return timeId;

	}

	/**
	 * this function sorts a 2d array on the basis
	 * of the first element of each one-dimensional array
	 * 
	 * @param array2d
	 *            - any 2d array
	 */
	private void sort2dArray(String[][] array2d) {

		Arrays.sort(array2d, new Comparator<String[]>() {
			@Override
			public int compare(final String[] entry1, final String[] entry2) {
				final String time1 = entry1[0];
				final String time2 = entry2[0];
				long value = Long.parseLong(time1) - Long.parseLong(time2);
				if (value < 0) {
					return -1;
				} else if (value == 0) {
					return 0;
				} else {
					return +1;
				}
			}
		});
	}

	/**
	 * 
	 * @return all events in storage as an array
	 */
	public static Event[] getAllEvents() {
		return DataManager.getAllEventsInStorage();
	}

	/**
	 * undo is irrelevant for this class
	 */
	@Override
	public Event[] undo() {
		return null;
	}

	/**
	 * undo is irrelevant for this class
	 */
	@Override
	public boolean isUndoable() {
		return false;
	}

	@Override
	public String errorMessage() {
		return "Reminders cannot be displayed";
	}

	/**
	 * @return string- command currently being executed in this case, reminder
	 */
	@Override
	public String getCommandName() {
		return "reminder";
	}
}
